﻿// Decompiled with JetBrains decompiler
// Type: TaleWorlds.CampaignSystem.TournamentGames.FightTournamentGame
// Assembly: TaleWorlds.CampaignSystem, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: E85F8C15-4DF6-4E9C-A58A-29177E40D07A
// Assembly location: D:\steam\steamapps\common\Mount & Blade II Bannerlord\bin\Win64_Shipping_Client\TaleWorlds.CampaignSystem.dll

using System;
using System.Collections.Generic;
using System.Linq;
using TaleWorlds.CampaignSystem.Extensions;
using TaleWorlds.CampaignSystem.Roster;
using TaleWorlds.CampaignSystem.Settlements;
using TaleWorlds.CampaignSystem.Settlements.Locations;
using TaleWorlds.Core;
using TaleWorlds.Library;
using TaleWorlds.Localization;

#nullable disable
namespace TaleWorlds.CampaignSystem.TournamentGames
{
  public class FightTournamentGame : TournamentGame
  {
    private const int LordLimitForEliteReward = 4;
    private const int EliteRewardLordCountToDivideRewards = 10;
    private const int EliteRewardGroupCount = 2;
    private const int RegularRewardMinimumValue = 1600;
    private const int RegularRewardMaximumValue = 5000;
    private const int ParticipateTournamentMinimumSkillLimit = 100;
    private const float RegularBannerRewardChance = 0.05f;
    public const int ParticipantTroopMinimumTierLimit = 3;
    private MBList<ItemObject> _possibleBannerRewardItemObjectsCache;
    private MBList<ItemObject> _possibleRegularRewardItemObjectsCache;
    private MBList<ItemObject> _possibleEliteRewardItemObjectsCache;

    internal static void AutoGeneratedStaticCollectObjectsFightTournamentGame(
      object o,
      List<object> collectedObjects)
    {
      ((TournamentGame) o).AutoGeneratedInstanceCollectObjects(collectedObjects);
    }

    protected override void AutoGeneratedInstanceCollectObjects(List<object> collectedObjects)
    {
      base.AutoGeneratedInstanceCollectObjects(collectedObjects);
    }

    public override int MaxTeamSize => 4;

    public override int MaxTeamNumberPerMatch => 4;

    public override int RemoveTournamentAfterDays => 15;

    public override int MaximumParticipantCount => 16;

    public FightTournamentGame(Town town)
      : base(town)
    {
      this.Mode = TournamentGame.QualificationMode.TeamScore;
    }

    public override bool CanBeAParticipant(CharacterObject character, bool considerSkills)
    {
      if (!character.IsHero)
        return character.Tier >= 3;
      return !considerSkills || character.HeroObject.GetSkillValue(DefaultSkills.OneHanded) >= 100 || character.HeroObject.GetSkillValue(DefaultSkills.TwoHanded) >= 100;
    }

    public override TextObject GetMenuText()
    {
      int variable1 = this.GetParticipantCharacters(Settlement.CurrentSettlement, false).Count<CharacterObject>((Func<CharacterObject, bool>) (p => p.IsHero));
      TextObject menuText = new TextObject("{=!}{TOURNAMENT_EXPLANATION} {PRIZE_EXPLANATION}");
      menuText.SetTextVariable("TOURNAMENT_EXPLANATION", GameTexts.FindText("str_fighting_menu_text"));
      TextObject variable2;
      if (variable1 > 0)
      {
        variable2 = new TextObject("{=GuWWKgEm}As you approach the arena, you overhear gossip about the contestants and prizes. Apparently there {?(NOBLE_COUNT > 1)}are {NOBLE_COUNT} lords{?}is 1 lord{\\?} with renowned fighting skills present in the city who plan to enter the tournament. Given this turnout, the organizers are offering {.a} \"{.%}{TOURNAMENT_PRIZE}{.%}\" for the victor.");
        variable2.SetTextVariable("NOBLE_COUNT", variable1);
        variable2.SetTextVariable("TOURNAMENT_PRIZE", this.Prize.Name);
      }
      else
      {
        variable2 = new TextObject("{=mnAdqeGu}As you approach the arena, you overhear gossip about the contestants and prizes. Apparently there are no lords who plan to compete, but the winner will still receive a {TOURNAMENT_PRIZE}.");
        variable2.SetTextVariable("TOURNAMENT_PRIZE", this.Prize.Name);
      }
      menuText.SetTextVariable("PRIZE_EXPLANATION", variable2);
      return menuText;
    }

    public override void OpenMission(Settlement settlement, bool isPlayerParticipating)
    {
      SandBoxMission.OpenTournamentFightMission(LocationComplex.Current.GetScene("arena", settlement.IsTown ? settlement.Town.GetWallLevel() : 1), (TournamentGame) this, settlement, settlement.Culture, isPlayerParticipating);
    }

    public override MBList<CharacterObject> GetParticipantCharacters(
      Settlement settlement,
      bool includePlayer = true)
    {
      MBList<CharacterObject> participantCharacters = new MBList<CharacterObject>();
      if (includePlayer)
        participantCharacters.Add(CharacterObject.PlayerCharacter);
      for (int index = 0; index < settlement.Parties.Count && participantCharacters.Count < this.MaximumParticipantCount; ++index)
      {
        Hero leaderHero = settlement.Parties[index].LeaderHero;
        if (this.CanNpcJoinTournament(leaderHero, participantCharacters, true))
        {
          if (leaderHero.CurrentSettlement != settlement)
            Debug.Print(leaderHero.StringId + " is in settlement.Parties list but current settlement is not, tournament settlement: " + settlement.StringId);
          participantCharacters.Add(leaderHero.CharacterObject);
        }
      }
      for (int index = 0; index < settlement.HeroesWithoutParty.Count && participantCharacters.Count < this.MaximumParticipantCount; ++index)
      {
        Hero hero = settlement.HeroesWithoutParty[index];
        if (this.CanNpcJoinTournament(hero, participantCharacters, true) && hero.IsLord)
        {
          if (hero.CurrentSettlement != settlement)
            Debug.Print(hero.StringId + " is in settlement.HeroesWithoutParty list but current settlement is not, tournament settlement: " + settlement.StringId);
          participantCharacters.Add(hero.CharacterObject);
        }
      }
      for (int index = 0; index < settlement.HeroesWithoutParty.Count && participantCharacters.Count < this.MaximumParticipantCount; ++index)
      {
        Hero hero = settlement.HeroesWithoutParty[index];
        if (this.CanNpcJoinTournament(hero, participantCharacters, true) && !hero.IsLord)
        {
          if (hero.CurrentSettlement != settlement)
            Debug.Print(hero.StringId + " is in settlement.HeroesWithoutParty list but current settlement is not, tournament settlement: " + settlement.StringId);
          participantCharacters.Add(hero.CharacterObject);
        }
      }
      for (int index = 0; index < settlement.Parties.Count && participantCharacters.Count < this.MaximumParticipantCount; ++index)
      {
        foreach (TroopRosterElement troopRosterElement in (List<TroopRosterElement>) settlement.Parties[index].MemberRoster.GetTroopRoster())
        {
          if (participantCharacters.Count < this.MaximumParticipantCount)
          {
            CharacterObject character = troopRosterElement.Character;
            if (character.IsHero && character.HeroObject.Clan == Clan.PlayerClan && this.CanNpcJoinTournament(character.HeroObject, participantCharacters, true))
            {
              if (character.HeroObject.CurrentSettlement != settlement)
                Debug.Print(character.HeroObject.StringId + " is in settlement.HeroesWithoutParty list but current settlement is not, tournament settlement: " + settlement.StringId);
              participantCharacters.Add(character);
            }
          }
          else
            break;
        }
      }
      int num1 = 0;
      int num2 = 0;
      int num3 = 0;
      if (participantCharacters.Count < this.MaximumParticipantCount && settlement.Town.GarrisonParty != null)
      {
        int num4 = this.MaximumParticipantCount - participantCharacters.Count;
        foreach (TroopRosterElement troopRosterElement in (List<TroopRosterElement>) settlement.Town.GarrisonParty.MemberRoster.GetTroopRoster())
        {
          if (this.CanBeAParticipant(troopRosterElement.Character, false))
          {
            if (!participantCharacters.Contains(troopRosterElement.Character) && troopRosterElement.Character.Tier == 3 && (double) num4 * 0.40000000596046448 > (double) num1)
            {
              participantCharacters.Add(troopRosterElement.Character);
              ++num1;
            }
            else if (!participantCharacters.Contains(troopRosterElement.Character) && troopRosterElement.Character.Tier == 4 && (double) num4 * 0.40000000596046448 > (double) num2)
            {
              participantCharacters.Add(troopRosterElement.Character);
              ++num2;
            }
            else if (!participantCharacters.Contains(troopRosterElement.Character) && troopRosterElement.Character.Tier == 5 && (double) num4 * 0.20000000298023224 > (double) num3)
            {
              participantCharacters.Add(troopRosterElement.Character);
              ++num3;
            }
          }
          if (participantCharacters.Count >= this.MaximumParticipantCount)
            break;
        }
      }
      if (participantCharacters.Count < this.MaximumParticipantCount)
      {
        List<CharacterObject> list = new List<CharacterObject>();
        this.GetUpgradeTargets((settlement != null ? settlement.Culture : Game.Current.ObjectManager.GetObject<CultureObject>("empire")).BasicTroop, ref list);
        int num5 = this.MaximumParticipantCount - participantCharacters.Count;
        foreach (CharacterObject characterObject in list)
        {
          if (!participantCharacters.Contains(characterObject) && characterObject.Tier == 3 && (double) num5 * 0.40000000596046448 > (double) num1)
          {
            participantCharacters.Add(characterObject);
            ++num1;
          }
          else if (!participantCharacters.Contains(characterObject) && characterObject.Tier == 4 && (double) num5 * 0.40000000596046448 > (double) num2)
          {
            participantCharacters.Add(characterObject);
            ++num2;
          }
          else if (!participantCharacters.Contains(characterObject) && characterObject.Tier == 5 && (double) num5 * 0.20000000298023224 > (double) num3)
          {
            participantCharacters.Add(characterObject);
            ++num3;
          }
          if (participantCharacters.Count >= this.MaximumParticipantCount)
            break;
        }
        if (!list.IsEmpty<CharacterObject>())
        {
label_64:
          while (participantCharacters.Count < this.MaximumParticipantCount)
          {
            list.Shuffle<CharacterObject>();
            int index = 0;
            while (true)
            {
              if (index < list.Count && participantCharacters.Count < this.MaximumParticipantCount)
              {
                participantCharacters.Add(list[index]);
                ++index;
              }
              else
                goto label_64;
            }
          }
        }
      }
      while (participantCharacters.Count < this.MaximumParticipantCount)
      {
        CultureObject cultureObject = settlement != null ? settlement.Culture : Game.Current.ObjectManager.GetObject<CultureObject>("empire");
        CharacterObject characterObject = (double) MBRandom.RandomFloat > 0.5 ? cultureObject.BasicTroop : cultureObject.EliteBasicTroop;
        participantCharacters.Add(characterObject);
      }
      this.SortTournamentParticipants(participantCharacters);
      return participantCharacters;
    }

    private bool CanNpcJoinTournament(
      Hero hero,
      MBList<CharacterObject> participantCharacters,
      bool considerSkills)
    {
      return hero != null && !hero.IsWounded && !hero.IsNoncombatant && !participantCharacters.Contains(hero.CharacterObject) && hero != Hero.MainHero && (double) hero.Age >= (double) Campaign.Current.Models.AgeModel.HeroComesOfAge && (hero.IsLord || hero.IsWanderer) && this.CanBeAParticipant(hero.CharacterObject, considerSkills);
    }

    private void GetUpgradeTargets(CharacterObject troop, ref List<CharacterObject> list)
    {
      if (!list.Contains(troop) && this.CanBeAParticipant(troop, false))
        list.Add(troop);
      foreach (CharacterObject upgradeTarget in troop.UpgradeTargets)
        this.GetUpgradeTargets(upgradeTarget, ref list);
    }

    private void SortTournamentParticipants(MBList<CharacterObject> participantCharacters)
    {
      for (int index1 = 0; index1 < participantCharacters.Count - 1; ++index1)
      {
        for (int index2 = participantCharacters.Count - 1; index2 > index1; --index2)
        {
          if (this.GetTroopPriorityPointForTournament(participantCharacters[index2]) > this.GetTroopPriorityPointForTournament(participantCharacters[index1]))
          {
            CharacterObject participantCharacter1 = participantCharacters[index2];
            CharacterObject participantCharacter2 = participantCharacters[index1];
            participantCharacters[index2] = participantCharacter2;
            participantCharacters[index1] = participantCharacter1;
          }
        }
      }
    }

    private int GetTroopPriorityPointForTournament(CharacterObject troop)
    {
      int num = 40000;
      if (troop == CharacterObject.PlayerCharacter)
        num += 80000;
      if (troop.IsHero)
        num += 20000;
      return !troop.IsHero || !troop.HeroObject.IsPlayerCompanion ? (troop.HeroObject?.Clan == null ? num + troop.Level : num + (int) troop.HeroObject.Clan?.Renown.Value) : num + 10000;
    }

    protected override ItemObject GetTournamentPrize(
      bool includePlayer,
      int lastRecordedLordCountForTournamentPrize)
    {
      int num1 = this.GetParticipantCharacters(this.Town.Settlement, includePlayer).Count<CharacterObject>((Func<CharacterObject, bool>) (p => p.IsHero));
      if (lastRecordedLordCountForTournamentPrize == num1 && this.Prize != null)
        return this.Prize;
      this._lastRecordedLordCountForTournamentPrize = num1;
      if (num1 < 4)
      {
        ItemObject tournamentPrize = (ItemObject) null;
        if ((double) MBRandom.RandomFloat < 0.05000000074505806)
        {
          if (this._possibleBannerRewardItemObjectsCache == null || this._possibleBannerRewardItemObjectsCache.IsEmpty<ItemObject>())
            this.CachePossibleBannerItems(false);
          tournamentPrize = this._possibleBannerRewardItemObjectsCache.GetRandomElement<ItemObject>();
        }
        if (tournamentPrize == null)
        {
          if (this._possibleRegularRewardItemObjectsCache == null || this._possibleRegularRewardItemObjectsCache.IsEmpty<ItemObject>())
            this.CachePossibleRegularRewardItems();
          int num2 = this._possibleRegularRewardItemObjectsCache.Count / 4;
          int maxValue = Math.Min(this._possibleRegularRewardItemObjectsCache.Count, num2 * (num1 + 1));
          tournamentPrize = this._possibleRegularRewardItemObjectsCache[MBRandom.RandomInt(Math.Max(0, maxValue - num2), maxValue)];
        }
        if (tournamentPrize != null)
          return tournamentPrize;
        if (this._possibleEliteRewardItemObjectsCache == null || this._possibleEliteRewardItemObjectsCache.IsEmpty<ItemObject>())
          this.CachePossibleEliteRewardItems();
        return this._possibleEliteRewardItemObjectsCache.GetRandomElement<ItemObject>();
      }
      if (this._possibleEliteRewardItemObjectsCache == null || this._possibleEliteRewardItemObjectsCache.IsEmpty<ItemObject>())
      {
        this.CachePossibleEliteRewardItems();
        this.CachePossibleBannerItems(true);
      }
      int minValue = 0;
      int maxValue1 = this._possibleEliteRewardItemObjectsCache.Count;
      if (num1 < 10)
        maxValue1 = this._possibleEliteRewardItemObjectsCache.Count / 2;
      else
        minValue = this._possibleEliteRewardItemObjectsCache.Count / 2;
      return this._possibleEliteRewardItemObjectsCache[MBRandom.RandomInt(minValue, maxValue1)];
    }

    private void CachePossibleBannerItems(bool isElite)
    {
      if (this._possibleBannerRewardItemObjectsCache == null)
        this._possibleBannerRewardItemObjectsCache = new MBList<ItemObject>();
      foreach (ItemObject rewardBannerItem in Campaign.Current.Models.BannerItemModel.GetPossibleRewardBannerItems())
      {
        if (isElite)
        {
          if (rewardBannerItem.BannerComponent.BannerLevel == 3)
            this._possibleEliteRewardItemObjectsCache.Add(rewardBannerItem);
        }
        else if (rewardBannerItem.BannerComponent.BannerLevel == 1 || rewardBannerItem.BannerComponent.BannerLevel == 2)
          this._possibleBannerRewardItemObjectsCache.Add(rewardBannerItem);
      }
    }

    private void CachePossibleRegularRewardItems()
    {
      if (this._possibleRegularRewardItemObjectsCache == null)
        this._possibleRegularRewardItemObjectsCache = new MBList<ItemObject>();
      MBList<ItemObject> collection = new MBList<ItemObject>();
      foreach (ItemObject itemObject in (List<ItemObject>) Items.All)
      {
        if (itemObject.Value > 1600 && itemObject.Value < 5000 && !itemObject.NotMerchandise && (itemObject.IsCraftedWeapon || itemObject.IsMountable || itemObject.ArmorComponent != null) && !itemObject.IsCraftedByPlayer)
        {
          if (itemObject.Culture == this.Town.Culture)
            this._possibleRegularRewardItemObjectsCache.Add(itemObject);
          else
            collection.Add(itemObject);
        }
      }
      if (this._possibleRegularRewardItemObjectsCache.IsEmpty<ItemObject>())
        this._possibleRegularRewardItemObjectsCache.AddRange((IEnumerable<ItemObject>) collection);
      this._possibleRegularRewardItemObjectsCache.Sort((Comparison<ItemObject>) ((x, y) => x.Value.CompareTo(y.Value)));
    }

    private void CachePossibleEliteRewardItems()
    {
      if (this._possibleEliteRewardItemObjectsCache == null)
        this._possibleEliteRewardItemObjectsCache = new MBList<ItemObject>();
      string[] strArray = new string[31]
      {
        "winds_fury_sword_t3",
        "bone_crusher_mace_t3",
        "tyrhung_sword_t3",
        "pernach_mace_t3",
        "early_retirement_2hsword_t3",
        "black_heart_2haxe_t3",
        "knights_fall_mace_t3",
        "the_scalpel_sword_t3",
        "judgement_mace_t3",
        "dawnbreaker_sword_t3",
        "ambassador_sword_t3",
        "heavy_nasalhelm_over_imperial_mail",
        "sturgian_helmet_closed",
        "full_helm_over_laced_coif",
        "desert_mail_coif",
        "heavy_nasalhelm_over_imperial_mail",
        "plumed_nomad_helmet",
        "ridged_northernhelm",
        "noble_horse_southern",
        "noble_horse_imperial",
        "noble_horse_western",
        "noble_horse_eastern",
        "noble_horse_battania",
        "noble_horse_northern",
        "special_camel",
        "western_crowned_helmet",
        "northern_warlord_helmet",
        "battania_warlord_pauldrons",
        "aserai_armor_02_b",
        "white_coat_over_mail",
        "spiked_helmet_with_facemask"
      };
      foreach (string objectName in strArray)
        this._possibleEliteRewardItemObjectsCache.Add(Game.Current.ObjectManager.GetObject<ItemObject>(objectName));
      this._possibleEliteRewardItemObjectsCache.Sort((Comparison<ItemObject>) ((x, y) => x.Value.CompareTo(y.Value)));
    }
  }
}
